﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using MessagePack;
using MessagePack.Resolvers;
using Microsoft.Extensions.Caching.Distributed;
using Newtonsoft.Json;

namespace Umi.Web.Utils.Storage
{
    /// <summary>
    /// 作用：分布式缓存扩展
    /// </summary>
    public static class DistributedCacheExtansions
    {
        /// <summary>
        /// 从缓存中读出对象，使用系统自带二进制序列化
        /// </summary>
        /// <param name="cache"></param>
        /// <param name="key">键</param>
        /// <returns></returns>
        public static object GetObject(this IDistributedCache cache, string key)
        {
            Trace.Assert(cache != null);
            byte[] data = cache.Get(key);
            if (data == null || data.Length == 0)
                return null;
            BinaryFormatter bf = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream())
            {
                ms.Write(data, 0, data.Length);
                ms.Position = 0;
                return bf.Deserialize(ms);
            }
        }

        /// <summary>
        /// 从缓存中读出对象，使用系统自带二进制序列化,泛型版本
        /// </summary>
        /// <param name="cache"></param>
        /// <param name="key">键</param>
        /// <returns></returns>
        public static T GetObject<T>(this IDistributedCache cache, string key)
        {
            return (T)GetObject(cache, key);
        }

        /// <summary>
        /// 将数据存入缓存
        /// </summary>
        /// <param name="cache"></param>
        /// <param name="key">键</param>
        /// <param name="obj">对象</param>
        public static void SetObject(this IDistributedCache cache, string key, object obj, DistributedCacheEntryOptions options = null)
        {
            Trace.Assert(cache != null && obj != null);
            BinaryFormatter bf = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream())
            {
                bf.Serialize(ms, obj);
                if (options != null)
                    cache.Set(key, ms.ToArray(), options);
                else
                    cache.Set(key, ms.ToArray());
            }
        }

        /// <summary>
        /// 使用json从缓存中读取对象
        /// </summary>
        /// <param name="cache"></param>
        /// <param name="key">键</param>
        /// <returns></returns>
        public static object GetObjectUseJson(this IDistributedCache cache, string key)
        {
            Trace.Assert(cache != null);//断言
            string json = cache.GetString(key);
            if (string.IsNullOrEmpty(json))
                return null;
            return JsonConvert.DeserializeObject(json);
        }

        /// <summary>
        /// 使用json从缓存中读取对象,泛型版本
        /// </summary>
        /// <param name="cache"></param>
        /// <param name="key">键</param>
        /// <returns></returns>
        public static T GetObjectUseJson<T>(this IDistributedCache cache, string key)
        {
            Trace.Assert(cache != null);//断言
            string json = cache.GetString(key);
            if (string.IsNullOrEmpty(json))
                return default(T);
            return JsonConvert.DeserializeObject<T>(json);
        }

        /// <summary>
        /// 将数据存入缓存,json格式
        /// </summary>
        /// <param name="cache"></param>
        /// <param name="key">键</param>
        /// <param name="obj">对象</param>
        public static void SetObjectUseJson(this IDistributedCache cache, string key, object obj, DistributedCacheEntryOptions options = null)
        {
            Trace.Assert(cache != null && obj != null);
            string json = JsonConvert.SerializeObject(obj);
            if (options != null)
                cache.SetString(key, json, options);
            else
                cache.SetString(key, json);
        }

        /// <summary>
        /// 使用MessagePack从缓存中读取对象,泛型版本
        /// </summary>
        /// <param name="cache"></param>
        /// <param name="key">键</param>
        /// <returns></returns>
        public static T GetObjectUseMsgPack<T>(this IDistributedCache cache, string key)
        {
            Trace.Assert(cache != null);//断言
            byte[] data = cache.Get(key);
            if (data == null || data.Length == 0)
                return default(T);
            return LZ4MessagePackSerializer.Deserialize<T>(data, ContractlessStandardResolver.Instance);
        }

        /// <summary>
        ///  将数据存入缓存,使用MessagePack
        /// </summary>
        /// <typeparam name="T">待序列化类型</typeparam>
        /// <param name="cache"></param>
        /// <param name="key">键</param>
        /// <param name="obj">对象</param>
        public static void SetObjectUseMsgPack<T>(this IDistributedCache cache, string key, T obj, DistributedCacheEntryOptions options = null)
        {
            Trace.Assert(cache != null && obj != null);
            if (options != null)
                cache.Set(key, LZ4MessagePackSerializer.Serialize(obj, ContractlessStandardResolver.Instance), options);
            else
                cache.Set(key, LZ4MessagePackSerializer.Serialize(obj, ContractlessStandardResolver.Instance));
        }
    }
}
